package com.hwg.shiliupro.aop;

import com.alibaba.druid.util.StringUtils;
import com.hwg.shiliupro.annotation.Authority;
import com.hwg.shiliupro.exception.Exception401;
import com.hwg.shiliupro.exception.Exception403;
import com.hwg.shiliupro.utils.AuthorityUtils;
import com.hwg.shiliupro.utils.HttpRequestUtils;
import com.hwg.shiliupro.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

//Filter > Interceptor > Aop 拦截顺序  先经过拦截器(token已经校验成功)  再经过AOP
@Aspect     //告诉spring使用了aop,声明为通知类
@Slf4j
@Component
public class AuthorityAopAdvice {
    //获取每一个接口上的权限标识(注解)   与用户请求时 他所拥有的的权限对比 判断用户是否拥有该权限
    //在切入点进行拦截
    //定义切入点  需要描述它匹配的方法 特征   它要依托于一个  无实际意义的方法
    //@Pointcut("execution(* com.hwg.rbac.controller.*.*(..))")
    //public void pt(){}


    //定义通知 只切入方法上使用了@Authority这个注解的方法 只对它们进行校验  其他有些方法无需校验是否有权限,例如登录
    @Around("@annotation(authority)")
    public Object around(ProceedingJoinPoint pjp, Authority authority) throws Throwable {
        //1、通过 Token 获取用户uId
        HttpServletRequest request = HttpRequestUtils.getRequest();
        String uId = JwtUtils.getMemberIdByJwtToken(request);
        log.info("AOP通过Token获取的用户id为:{}",uId);
        if(StringUtils.isEmpty(uId)){
            throw new Exception401(401,"token不存在/校验token失败");
        }
        //2、获取注解上的接口权限标识
        String value = authority.value();
        //3、校验是否有权限
        Boolean verify = AuthorityUtils.verify(uId, value);
        if(verify){
            //有权限 执行目标方法
            Object proceed = pjp.proceed();
            return proceed;
        }
        log.info("用户没有权限");
        throw new Exception403(403,"您暂无此权限");
//        return new R(403,"您暂无此权限");
    }

}
